home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-17 | 71.0 KB | 2,334 lines |
- #! /usr/local/bin/perl
- ##---------------------------------------------------------------------------##
- ## File:
- ## MHonArc
- ## Author:
- ## Earl Hood ehood@convex.com
- ## Contributers:
- ## Steve Pacenka <sp17@cornell.edu>,
- ## Achim Bohnet <ach@rosat.mpe-garching.mpg.de>,
- ## Achille Petrilli <Achille.Petrilli@MACMAIL.CERN.CH>
- ## Description:
- ## MHonArc is a Perl program to convert mail to HTML. See
- ## accompany documentation for full details.
- ##---------------------------------------------------------------------------##
- ## MHonArc -- Internet mail-to-HTML converter
- ## Copyright (C) 1995,1996 Earl Hood, ehood@convex.com
- ##
- ## This program is free software; you can redistribute it and/or modify
- ## it under the terms of the GNU General Public License as published by
- ## the Free Software Foundation; either version 2 of the License, or
- ## (at your option) any later version.
- ##
- ## This program is distributed in the hope that it will be useful,
- ## but WITHOUT ANY WARRANTY; without even the implied warranty of
- ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ## GNU General Public License for more details.
- ##
- ## You should have received a copy of the GNU General Public License
- ## along with this program; if not, write to the Free Software
- ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ##---------------------------------------------------------------------------##
-
- #############################################################################
- #############################################################################
- package main;
-
- $VERSION = "1.2.2"; # Version number
-
- ##---------------------------------------------------------------------------##
- ## Main routine ##
- ##---------------------------------------------------------------------------##
-
- &prestart();
- &get_cli_opts();
- &doit();
-
- ##---------------------------------------------------------------------------##
- ## SubRoutines ##
- ##---------------------------------------------------------------------------##
- ##---------------------------------------------------------------------------
- ## prestart() does some initialization stuff.
- ##
- sub prestart {
- ## Turn off buffered I/O to terminal
- select(STDOUT); $| = 1;
-
- unshift(@INC, 'lib'); # Should I leave this line in?
-
- ## Check what system we are executing under
- require 'osinit.pl' || &error("ERROR: Unable to require osinit.pl");
- &'OSinit();
-
- ## Require key libraries
- require 'newgetopt.pl' || &error("ERROR: Unable to require newgetopt.pl");
- require 'timelocal.pl' || &error("ERROR: Unable to require timelocal.pl");
- require 'readmail.pl' || &error("ERROR: Unable to require readmail.pl");
- require 'mhdb.pl' || &error("ERROR: Unable to require mhdb.pl");
- require 'mhutil.pl' || &error("ERROR: Unable to require mhutil.pl");
-
- ## The %Zone array should be augmented to contain all timezone
- ## specifications with the positive/negative hour offset from UTC
- ## (GMT). (There has got to be a better way to handle timezones)
- %Zone = (
- "UTC", 0, # Universal Coordinated Time
- "GMT", 0, # Greenwich Mean Time
- "AST", 4, # Atlantic Standard Time
- "ADT", 3, # Atlantic Daylight Time
- "EST", 5, # Eastern Standard Time
- "EDT", 4, # Eastern Daylight Time
- "CST", 6, # Central Standard Time
- "CDT", 5, # Central Daylight Time
- "MST", 7, # Mountain Standard Time
- "MDT", 6, # Mountain Daylight Time
- "PST", 8, # Pacific Standard Time
- "PDT", 7, # Pacific Daylight Time
- );
- ## Assoc array listing mail header fields to exclude in output.
- ## Each key is treated as a regular expression with '^' prepended
- ## to it.
- %HFieldsExc = (
- 'content-', 1, # Mime headers
- 'errors-to', 1,
- 'forward', 1, # Forward lines (MH may add these)
- 'lines', 1,
- 'message-id', 1,
- 'mime-', 1, # Mime headers
- 'nntp-', 1,
- 'originator', 1,
- 'path', 1,
- 'precedence', 1,
- 'received', 1, # MTA added headers
- 'replied', 1,
- 'return-path', 1, # MH creates this during inc
- 'status', 1,
- 'via', 1,
- 'x-', 1, # Non-standard headers
- );
- ## Asocc arrays defining HTML formats to apply to header fields
- %HeadFields = (
- "-default-", "",
- );
- %HeadHeads = (
- "-default-", "em",
- );
- @FieldOrder = (
- 'to',
- 'subject',
- 'from',
- 'date',
- '-extra-',
- );
- %FieldODefs = (
- 'to', 1,
- 'subject', 1,
- 'from', 1,
- 'date', 1,
- );
- $NumOfMsgs = 0; # Total number of messages
- $LastMsgNum = -1; # Message number of last message
- %Message = (); # Message bodies
- %MsgHead = (); # Message heads
- %MsgHtml = (); # Flag if message is html
- %Subject = (); # Message subjects
- %From = (); # Message froms
- %Date = (); # Message dates
- %MsgId = (); # Message Ids to indexes
- %IndexNum = (); # Index key to message number
- %Derived = (); # Derived files for messages
- %Refs = (); # Message references
- %Follow = (); # Message follow-ups
- %FolCnt = (); # Number of follow-ups
- %ContentType= (); # Base content-type of messages
- %Icons = (); # Icon URLs for content-types
- %AddIndex = (); # Flags for messages that must be written
- $bs = "\b";
- $Url = '(http://|ftp://|afs://|wais://|telnet://|gopher://|' .
- 'news:|nntp:|mid:|cid:|mailto:|prospero:)';
- $MLCP = 0;
- $ISLOCK = 0;
- $SLOW = 0;
-
- ## Get date
- $curdate = &getdate(0);
- $locdate = &getdate(1);
-
- ## Set default filter libraries
- @Requires = (
-
- "mhexternal.pl",
- "mhtxthtml.pl",
- "mhtxtplain.pl",
- "mhtxtsetext.pl",
-
- );
-
- ## Default filters
- %MIMEFilters = (
-
- "application/mac-binhex40", "m2h_external'filter",
- "application/octet-stream", "m2h_external'filter",
- "application/oda", "m2h_external'filter",
- "application/pdf", "m2h_external'filter",
- "application/postscript", "m2h_external'filter",
- "application/rtf", "m2h_external'filter",
- "application/x-bcpio", "m2h_external'filter",
- "application/x-cpio", "m2h_external'filter",
- "application/x-csh", "m2h_external'filter",
- "application/x-dvi", "m2h_external'filter",
- "application/x-gtar", "m2h_external'filter",
- "application/x-hdf", "m2h_external'filter",
- "application/x-latex", "m2h_external'filter",
- "application/x-mif", "m2h_external'filter",
- "application/x-netcdf", "m2h_external'filter",
- "application/x-patch", "m2h_text_plain'filter",
- "application/x-sh", "m2h_external'filter",
- "application/x-shar", "m2h_external'filter",
- "application/x-sv4cpio", "m2h_external'filter",
- "application/x-sv4crc", "m2h_external'filter",
- "application/x-tar", "m2h_external'filter",
- "application/x-tcl", "m2h_external'filter",
- "application/x-tex", "m2h_external'filter",
- "application/x-texinfo", "m2h_external'filter",
- "application/x-troff", "m2h_external'filter",
- "application/x-troff-man", "m2h_external'filter",
- "application/x-troff-me", "m2h_external'filter",
- "application/x-troff-ms", "m2h_external'filter",
- "application/x-ustar", "m2h_external'filter",
- "application/x-wais-source", "m2h_external'filter",
- "application/zip", "m2h_external'filter",
- "audio/basic", "m2h_external'filter",
- "audio/x-aiff", "m2h_external'filter",
- "audio/x-wav", "m2h_external'filter",
- "image/gif", "m2h_external'filter",
- "image/ief", "m2h_external'filter",
- "image/jpeg", "m2h_external'filter",
- "image/tiff", "m2h_external'filter",
- "image/x-bmp", "m2h_external'filter",
- "image/x-cmu-raster", "m2h_external'filter",
- "image/x-pbm", "m2h_external'filter",
- "image/x-pcx", "m2h_external'filter",
- "image/x-pgm", "m2h_external'filter",
- "image/x-pict", "m2h_external'filter",
- "image/x-pnm", "m2h_external'filter",
- "image/x-portable-anymap", "m2h_external'filter",
- "image/x-portable-bitmap", "m2h_external'filter",
- "image/x-portable-graymap", "m2h_external'filter",
- "image/x-portable-pixmap", "m2h_external'filter",
- "image/x-ppm", "m2h_external'filter",
- "image/x-rgb", "m2h_external'filter",
- "image/x-xbitmap", "m2h_external'filter",
- "image/x-xbm", "m2h_external'filter",
- "image/x-xpixmap", "m2h_external'filter",
- "image/x-xpm", "m2h_external'filter",
- "image/x-xwd", "m2h_external'filter",
- "image/x-xwindowdump", "m2h_external'filter",
- "message/partial", "m2h_text_plain'filter",
- "text/html", "m2h_text_html'filter",
- "text/plain", "m2h_text_plain'filter",
- "text/richtext", "m2h_text_plain'filter",
- "text/setext", "m2h_text_setext'filter",
- "text/tab-separated-values", "m2h_text_plain'filter",
- "text/x-html", "m2h_text_html'filter",
- "text/x-setext", "m2h_text_setext'filter",
- "video/mpeg", "m2h_external'filter",
- "video/quicktime", "m2h_external'filter",
- "video/x-msvideo", "m2h_external'filter",
- "video/x-sgi-movie", "m2h_external'filter",
-
- );
-
- ## Default filter arguments
- %MIMEFiltersArgs = (
-
- "image/gif", "inline",
- "image/x-xbitmap", "inline",
- "image/x-xbm", "inline",
- );
-
- ## Grab environment variable settings
- ##
- $DBFILE = ($ENV{'M2H_DBFILE'} ? $ENV{'M2H_DBFILE'} :
- ($MSDOS ? "mhonarc.db" : ".mhonarc.db"));
- $DOCURL = ($ENV{'M2H_DOCURL'} ? $ENV{'M2H_DOCURL'} :
- 'http://www.oac.uci.edu/indiv/ehood/mhonarc.html');
- $FOOTER = ($ENV{'M2H_FOOTER'} ? $ENV{'M2H_FOOTER'} : "");
- $HEADER = ($ENV{'M2H_HEADER'} ? $ENV{'M2H_HEADER'} : "");
- $IDXNAME = ($ENV{'M2H_IDXFNAME'} ? $ENV{'M2H_IDXFNAME'} :
- "maillist.html");
- $IDXSIZE = ($ENV{'M2H_IDXSIZE'} ? $ENV{'M2H_IDXSIZE'} : "");
- $TIDXNAME = ($ENV{'M2H_TIDXFNAME'} ? $ENV{'M2H_TIDXFNAME'} :
- "threads.html");
- $OUTDIR = ($ENV{'M2H_OUTDIR'} ? $ENV{'M2H_OUTDIR'} : $CURDIR);
- $FMTFILE = ($ENV{'M2H_RCFILE'} ? $ENV{'M2H_RCFILE'} : "");
- $TTITLE = ($ENV{'M2H_TTITLE'} ? $ENV{'M2H_TTITLE'} :
- "Mail Thread Index");
- $TITLE = ($ENV{'M2H_TITLE'} ? $ENV{'M2H_TITLE'} : "Mail Index");
- $MAILTOURL = ($ENV{'M2H_MAILTOURL'} ? $ENV{'M2H_MAILTOURL'} : "");
- $FROM = ($ENV{'M2H_MSGSEP'} ? $ENV{'M2H_MSGSEP'} : '^From ');
- $LOCKFILE = ($ENV{'M2H_LOCKFILE'} ? $ENV{'M2H_LOCKFILE'} :
- ($MSDOS ? "mhonarc.lck" : ".mhonarc.lck"));
- $LOCKTRIES = ($ENV{'M2H_LOCKTRIES'} ? $ENV{'M2H_LOCKTRIES'} : 10);
- $LOCKDELAY = ($ENV{'M2H_LOCKDELAY'} ? $ENV{'M2H_LOCKDELAY'} : 3);
- $MAXSIZE = ($ENV{'M2H_MAXSIZE'} ? $ENV{'M2H_MAXSIZE'} : "");
- $THREAD = (defined($ENV{'M2H_THREAD'}) ? $ENV{'M2H_THREAD'} : 1);
- $TLEVELS = ($ENV{'M2H_TLEVELS'} ? $ENV{'M2H_TLEVELS'} : 3);
-
- $LIBEG = ''; # List open template for main index
- $LIEND = ''; # List close template for main index
- $LITMPL = ''; # List item template
- $TFOOT = ''; # Thread index footer
- $THEAD = ''; # Thread index header
- $TLITXT = ''; # Thread index list item template
-
- $MSGFOOT = ''; # Message footer
- $MSGHEAD = ''; # Message header
- $TOPLINKS = ''; # Message links at top of message
- $BOTLINKS = ''; # Message links at bottom of message
- $NEXTBUTTON = ''; # Next button template
- $NEXTBUTTONIA = ''; # Next inactive button template
- $PREVBUTTON = ''; # Previous button template
- $PREVBUTTONIA = ''; # Previous inactive button template
- $NEXTLINK = ''; # Next link template
- $NEXTLINKIA = ''; # Next inactive link template
- $PREVLINK = ''; # Previous link template
- $PREVLINKIA = ''; # Previous inactive link template
-
- $IDXPGBEG = ''; # Beginning of main index page
- $IDXPGEND = ''; # Ending of main index page
- $TIDXPGBEG = ''; # Beginning of thread index page
- $TIDXPGEND = ''; # Ending of thread index page
-
- $MSGPGBEG = ''; # Beginning of message page
- $MSGPGEND = ''; # Ending of message page
-
- # $PREVBL = '[Prev]'; # No longer used
- # $NEXTBL = '[Next]'; # No longer used
- # $IDXBL = '[Index]'; # No longer used
- # $TIDXBL = '[Thread]'; # No longer used
-
- # $PREVFL = 'Prev'; # No longer used
- # $NEXTFL = 'Next'; # No longer used
- # $IDXFL = 'Index'; # No longer used
- # $TIDXFL = 'Thread'; # No longer used
-
- ## Init some flags
- ##
- $NOSORT = 0; $REVSORT = 0; $NONEWS = 0; $TREVERSE = 0;
- $NOMAILTO = 0; $NOURL = 0; $SUBSORT = 0; $NODOC = 0;
- $TSUBSORT = 0;
- $UMASK = sprintf("%o",umask) if $UNIX;
-
- $X = "\034"; # Value separator (should equal $;)
- # NOTE: Older versions used this variable for
- # the multiple field separator in parsed
- # message headers. $'FieldSep should
- # now be used (readmail.pl).
- }
- ##---------------------------------------------------------------------------
- ## get_cli_opts() is responsible for grabbing command-line options
- ## and also settings the resource file.
- ##
- sub get_cli_opts {
- local($tmp, @array);
-
- &error(qq{Try "$PROG -help" for usage information}) unless
- &NGetOpt(
- "add", # Add a message to archive
- "dbfile=s", # Database/state filename for mhonarc archive
- "docurl=s", # URL to mhonarc documentation
- "editidx", # Change index page layout only
- "footer=s", # File containing user text for bottom of index page
- "force", # Perform archive operation even if unable to lock
- "genidx", # Generate an index based upon archive contents
- "header=s", # File containing user text for top of index page
- "idxfname=s", # File name of index page
- "idxsize=i", # Maximum number of messages shown in indexes
- "lockdelay=i", # Time delay in seconds between lock tries
- "locktries=i", # Number of tries in locking an archive
- "mailtourl=s", # URL to use for e-mail address hyperlinks
- "maxsize=i", # Maximum number of messages allowed in archive
- "mbox", # Use mailbox format (ignored now)
- "mh", # Use MH mail folders format (ignored now)
- "msgsep=s", # Message separator for mailbox files
- "nodoc", # Do not print link to doc at end of index page
- "nomailto", # Do not add in mailto links for e-mail addresses
- "nonews", # Do not add links to newsgroups
- "noreverse", # List messages in normal order
- "nosort", # Do not sort
- "nothread", # Do not create threaded index
- "notreverse", # List oldest thread first
- "notsubsort", # Do sort listed threads by subject; sort by date
- "nourl", # Do not make URL hyperlinks
- "outdir=s", # Destination of HTML files
- "quiet", # No status messages while running
- "rcfile=s", # Resource file for mhonarc
- "reverse", # List messages in reverse order
- "revsort", # Perform reverse sorting on dates
- "rmm", # Remove messages from an archive
- "savemem", # Write message data while processing
- "scan", # List out archive contents to terminal
- "single", # Convert a single message to HTML
- "sort", # Sort messages in increasing date order
- "subsort", # Sort message by subject
- "tidxfname=s", # File name of threaded index page
- "time", # Print processing time
- "title=s", # Title of index page
- "ttitle=s", # Title of threaded index page
- "thread", # Create threaded index
- "tlevels=i", # Maximum # of nested lists in threaded index
- "treverse", # List most recent thread first
- "tsubsort", # Sort listed threads by subject
- "umask=i", # Set umask of process
-
- "help" # A brief usage message
- );
- &usage() if defined($opt_help);
-
- ## These options have NO resource file equivalent.
- ##
- $ADD = defined($opt_add);
- $RMM = defined($opt_rmm);
- $SCAN = defined($opt_scan);
- $QUIET = defined($opt_quiet);
- $EDITIDX = defined($opt_editidx);
- if (defined($opt_genidx)) {
- $IDXONLY = 1; $QUIET = 1;
- } else {
- $IDXONLY = 0;
- }
- if (defined($opt_single)) {
- $SINGLE = 1; $QUIET = 1;
- } else {
- $SINGLE = 0;
- }
- &usage() unless ($#ARGV >= 0) || $ADD || $SINGLE ||
- $EDITIDX || $SCAN || $IDXONLY;
- $FMTFILE = $opt_rcfile if $opt_rcfile;
- $LOCKTRIES = $opt_locktries if ($opt_locktries > 0);
- $LOCKDELAY = $opt_lockdelay if ($opt_lockdelay > 0);
- $FORCELOCK = defined($opt_force);
-
- ## These options must be grabbed before reading the database file
- ## since these options may tells us where the database file is.
- ##
- $OUTDIR = $opt_outdir if $opt_outdir;
- if (!(-r $OUTDIR) || !(-w $OUTDIR) || !(-x $OUTDIR)) {
- &error("ERROR: Unable to access $OUTDIR");
- }
- $DBFILE = $opt_dbfile if $opt_dbfile;
-
- ## Create lockfile
- ##
- $LOCKFILE = "${OUTDIR}${DIRSEP}${LOCKFILE}";
- if (!$SINGLE && !&create_lock_file($LOCKFILE, 1, 0, 0)) {
- print STDOUT "Trying to lock mail archive in $OUTDIR ...\n"
- unless $QUIET;
- if (!&create_lock_file($LOCKFILE,
- $LOCKTRIES-1,
- $LOCKDELAY,
- $FORCELOCK)) {
- &error("ERROR: Unable to create $LOCKFILE after $LOCKTRIES tries");
- }
- }
- ## Race condition exists: if process is terminated before termination
- ## handlers set, lock file will not get removed.
- ##
- &set_handler();
-
- ## Check if we need to access database file
- ##
- if ($ADD || $EDITIDX || $RMM || $SCAN || $IDXONLY) {
- $DBFILE = ".mail2html.db"
- unless (-e "${OUTDIR}${DIRSEP}${DBFILE}") ||
- (!-e "${OUTDIR}${DIRSEP}.mail2html.db");
- if (-e "${OUTDIR}${DIRSEP}${DBFILE}") {
- eval qq%require "${OUTDIR}${DIRSEP}${DBFILE}"%;
- &error("ERROR: Database read error of ",
- "${OUTDIR}${DIRSEP}${DBFILE}:\n\t$@") if $@;
- $OldNOSORT = $NOSORT;
- $OldSUBSORT = $SUBSORT;
- $OldREVSORT = $REVSORT;
- if ($VERSION ne $DbVERSION) {
- warn "Warning: Database ($DbVERSION) != ",
- "program ($VERSION) version.\n";
- }
- }
- if ($#ARGV < 0) { $ADDSINGLE = 1; } # See if adding single mesg
- else { $ADDSINGLE = 0; }
- $ADD = 'STDIN';
- }
- $OldTITLE = $TITLE;
- $OldTHREAD = $THREAD;
- $OldTTITLE = $TTITLE;
-
- ## Get highest message number
- if ($ADD) {
- $LastMsgNum = &get_last_msg_num();
- } else {
- $LastMsgNum = -1;
- }
-
- ## Remove lock file if scanning messages
- ##
- if ($SCAN) {
- &clean_up();
- }
-
- ## Read resource file (I initially used the term 'format file').
- ## Look for resource in outdir if not absolute path or not
- ## existing according to current value.
- ##
- if ($FMTFILE) {
- $FMTFILE = "${OUTDIR}${DIRSEP}$FMTFILE"
- unless ($FMTFILE =~ m%^/%) || (-e $FMTFILE);
- &read_fmt_file($FMTFILE);
- }
-
- ## Require MIME filters and other libraries
- ##
- unshift(@INC, @PerlINC);
- if (!$EDITIDX && !$SCAN && !$RMM) {
- &remove_dups(*Requires);
- print STDOUT "Requiring MIME filter libraries ...\n" unless $QUIET;
- foreach (@Requires) {
- print STDOUT "\t$_\n" unless $QUIET;
- eval qq{require "$_"};
- &error("ERROR: Unable to require ${_}:\n\t$@") if $@;
- }
- ## Register message header formatter to readmail library
- $readmail'FormatHeaderFunc = "main'htmlize_header";
- }
-
- ## Get other command-line options
- ##
- $DBFILE = $opt_dbfile if $opt_dbfile; # Set again to override db
- $DOCURL = $opt_docurl if $opt_docurl;
- $FOOTER = $opt_footer if $opt_footer;
- $FROM = $opt_msgsep if $opt_msgsep;
- $HEADER = $opt_header if $opt_header;
- $IDXNAME = $opt_idxfname if $opt_idxfname;
- $IDXSIZE = $opt_idxsize if $opt_idxsize;
- $IDXSIZE *= -1 if $IDXSIZE < 0;
- $OUTDIR = $opt_outdir if $opt_outdir; # Set again to override db
- $MAILTOURL = $opt_mailtourl if $opt_mailtourl;
- $MAXSIZE = $opt_maxsize if $opt_maxsize;
- $MAXSIZE = "" if $MAXSIZE < 0;
- $TIDXNAME = $opt_tidxfname if $opt_tidxfname;
- $TITLE = $opt_title if $opt_title;
- $TLEVELS = $opt_tlevels if $opt_tlevels;
- $TTITLE = $opt_ttitle if $opt_ttitle;
-
- $NODOC = 1 if defined($opt_nodoc);
- $NOMAILTO = 1 if defined($opt_nomailto);
- $NONEWS = 1 if defined($opt_nonews);
- $NOURL = 1 if defined($opt_nourl);
- $SLOW = 1 if defined($opt_savemem);
- $THREAD = 1 if defined($opt_thread);
- $THREAD = 0 if defined($opt_nothread);
- $TREVERSE = 1 if defined($opt_treverse);
- $TREVERSE = 0 if defined($opt_notreverse);
- $TSUBSORT = 1 if defined($opt_tsubsort);
- $TSUBSORT = 0 if defined($opt_notsubsort);
-
- ## Set umask
- if ($UNIX) {
- $UMASK = $opt_umask if $opt_umask;
- eval 'umask oct($UMASK)';
- }
-
- ## Get sort method
- ##
- $SORTCHNG = 0;
- if (defined($opt_nosort)) { # No sorting takes highest precedence
- $NOSORT = 1; $SUBSORT = 0;
- } elsif (defined($opt_subsort)) { # Subject sort
- $SUBSORT = 1; $NOSORT = 0;
- } elsif (defined($opt_sort)) { # Regular sort is last
- $NOSORT = 0; $SUBSORT = 0;
- }
- ## Check for listing order
- ##
- if (defined($opt_noreverse)) {
- $REVSORT = 0;
- } elsif (defined($opt_reverse) || defined($opt_revsort)) {
- $REVSORT = 1;
- }
- $SORTCHNG = 1 if (($OldNOSORT != $NOSORT) ||
- ($OldSUBSORT != $SUBSORT) ||
- ($OldREVSORT != $REVSORT));
-
- ## Check if all messages must be updated
- ##
- if ($SORTCHNG || $RMM || $EDITIDX ||
- ($OldTITLE ne $TITLE) ||
- ($OldTTITLE ne $TTITLE) ||
- ($THREAD != $OldTHREAD)) {
- $UPDATE_ALL = 1;
- } else {
- $UPDATE_ALL = 0;
- }
-
- ## Check index resources
- $IDXPGBEG = join('',
- '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">',
- "\n",
- "<HTML>\n",
- "<HEAD>\n",
- '<TITLE>$IDXTITLE$</TITLE>', "\n",
- "</HEAD>\n",
- "<BODY>\n",
- '<H1>$IDXTITLE$</H1>', "\n")
- unless $IDXPGBEG;
- $IDXPGEND = join('',
- "</BODY>\n",
- "</HTML>\n")
- unless $IDXPGEND;
-
- if ($THREAD) {
- $LIBEG = join('', "<UL>\n",
- '<LI><A HREF="$TIDXFNAME$">Thread Index</A></LI>',
- "\n",
- "</UL>\n<HR>\n<UL>\n")
- unless $LIBEG;
- $THEAD = join('', "<UL>\n",
- '<LI><A HREF="$IDXFNAME$">Main Index</A></LI>',
- "\n",
- "</UL>\n<HR>\n")
- unless $THEAD;
- $TLITXT = '($NUMFOLUP$) <STRONG>$SUBJECT:40$</STRONG>, ' .
- '<EM>$FROMNAME$</EM>'
- unless $TLITXT;
- $TIDXPGBEG = join('',
- "<!DOCTYPE HTML PUBLIC ",
- qq{"-//IETF//DTD HTML 2.0//EN">\n},
- "<HTML>\n",
- "<HEAD>\n",
- '<TITLE>$TIDXTITLE$</TITLE>', "\n",
- "</HEAD>\n",
- "<BODY>\n",
- '<H1>$TIDXTITLE$</H1>', "\n")
- unless $TIDXPGBEG;
- $TIDXPGEND = join('',
- "</BODY>\n",
- "</HTML>\n")
- unless $TIDXPGEND;
-
- } else {
- $LIBEG = "<HR>\n<UL>\n" unless $LIBEG;
- }
- $LIEND = "</UL>\n"
- unless $LIEND;
- $LITMPL = join('', '<LI><STRONG>$SUBJECT$</STRONG>', "\n",
- '<UL><LI><EM>From</EM>: $FROM$</LI></UL>' , "\n",
- "</LI>\n")
- unless $LITMPL;
-
- ## Message resources
- $MSGPGBEG = join('',
- '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">',
- "\n",
- "<HTML>\n",
- "<HEAD>\n",
- '<TITLE>$SUBJECTNA:72$</TITLE>', "\n",
- '<LINK REV="made" HREF="mailto:$FROMADDR$">', "\n",
- "</HEAD>\n",
- "<BODY>\n")
- unless $MSGPGBEG;
- $MSGPGEND = join('',
- "</BODY>\n",
- "</HTML>\n")
- unless $MSGPGEND;
-
- # Check for next/prev message link resources. Must check for
- # older variables to preserve capatibility.
- $PREVBL = '[Prev]' unless $PREVBL;
- $NEXTBL = '[Next]' unless $NEXTBL;
- $IDXBL = '[Index]' unless $IDXBL;
- $TIDXBL = '[Thread]' unless $TIDXBL;
- $NEXTFL = 'Next' unless $NEXTFL;
- $PREVFL = 'Prev' unless $PREVFL;
-
- $NEXTBUTTON = '<A HREF="$NEXTMSG$">' . $NEXTBL . '</A>'
- unless $NEXTBUTTON;
- $PREVBUTTON = '<A HREF="$PREVMSG$">' . $PREVBL . '</A>'
- unless $PREVBUTTON;
- $NEXTBUTTONIA = ''
- unless $PREVBUTTONIA;
- $PREVBUTTONIA = ''
- unless $PREVBUTTONIA;
-
- $NEXTLINK = join('',
- "<LI>$NEXTFL: <STRONG>",
- '<A HREF="$NEXTMSG$">$NEXTSUBJECT$</A>',
- "</STRONG></LI>\n") unless $NEXTLINK;
- $NEXTLINKIA = '' unless $NEXTLINKIA;
- $PREVLINK = join('',
- "<LI>$PREVFL: <STRONG>",
- '<A HREF="$PREVMSG$">$PREVSUBJECT$</A>',
- "</STRONG></LI>\n") unless $PREVLINK;
- $PREVLINKIA = '' unless $PREVLINKIA;
-
- if (!$TOPLINKS) {
- $TOPLINKS = join('',
- "<HR>\n",
- '$PREVBUTTON$$NEXTBUTTON$',
- '<A HREF="$IDXFNAME$#$MSGNUM$">', $IDXBL, '</A>');
- $TOPLINKS .= join('',
- '<A HREF="$TIDXFNAME$#$MSGNUM$">', $TIDXBL, '</A>')
- if $THREAD;
- }
-
- if (!$BOTLINKS) {
- $BOTLINKS = join('',
- "<HR>\n",
- "<UL>\n",
- '$PREVLINK$',
- '$NEXTLINK$',
- "<LI>Index(es):\n",
- "<UL>\n",
- '<LI><A HREF="$IDXFNAME$#$MSGNUM$">',
- "<STRONG>Main</STRONG></A></LI>\n");
- $BOTLINKS .= join('',
- '<LI><A HREF="$TIDXFNAME$#$MSGNUM$">',
- "<STRONG>Thread</STRONG></A></LI>\n")
- if $THREAD;
- $BOTLINKS .= "</UL>\n</LI>\n</UL>\n";
- }
-
- ## Set unknown icon
- $Icons{'unknown'} = $Icons{'text/plain'} unless $Icons{'unknown'};
-
- ## Set some other variables
- $IDXPATHNAME = "${OUTDIR}${DIRSEP}${IDXNAME}";
- $TIDXPATHNAME = "${OUTDIR}${DIRSEP}${TIDXNAME}";
-
- ## Create dynamic subroutines.
- &create_routines();
-
- $TIME = defined($opt_time);
- $StartTime = (times)[0] if ($TIME);
- }
- ##---------------------------------------------------------------------------
- sub doit {
- ## Check for non-archive modification modes.
- if ($SCAN) {
- &scan();
- &quit(0);
- } elsif ($SINGLE) {
- &single();
- &quit(0);
- }
-
- ## Following causes changes to an archive
- local($mesg, $tmp, $index, $sub, $from, $i, $date, @array,
- @array2, $tmp2, %fields);
-
- $i = $NumOfMsgs;
- ##-------------------##
- ## Read mail folders ##
- ##-------------------##
- if ($EDITIDX || $IDXONLY) {
- print STDOUT "Editing $OUTDIR layout ...\n" unless $QUIET;
-
- } elsif ($RMM) { ## Delete messages
- print STDOUT "Removing messages from $OUTDIR ...\n"
- unless $QUIET;
- &rmm(*ARGV);
-
- } elsif ($ADDSINGLE) { ## Adding single message
- print STDOUT "Adding message to $OUTDIR\n" unless $QUIET;
- $handle = $ADD;
-
- ## Read mail head
- ($index,$from,$date,$sub,$header) =
- &read_mail_header($handle, *mesg, *fields);
-
- if ($index ne '') {
- ($From{$index},$Date{$index},$Subject{$index}) =
- ($from,$date,$sub);
-
- $AddIndex{$index} = 1;
- $IndexNum{$index} = &getNewMsgNum();
-
- $MsgHead{$index} = $mesg;
- $MsgHead{$index} .= "<HR>\n" unless $mesg =~ /^\s*$/;
-
- ## Read rest of message
- $Message{$index} = &read_mail_body(
- $handle,
- $index,
- $header,
- *fields);
- }
-
- } else { ## Adding/converting mail{boxes,folders}
- print STDOUT ($ADD ? "Adding" : "Converting"), " messages to $OUTDIR"
- unless $QUIET;
- local($mbox, $mesgfile, @files);
- foreach $mbox (@ARGV) {
- if (-d $mbox) { # MH mail folder
- if (!opendir(MAILDIR, $mbox)) {
- warn "\nWarning: Unable to open $mbox\n";
- next;
- }
- $MBOX = 0; $MH = 1;
- print STDOUT "\nReading $mbox " unless $QUIET;
- @files = sort numerically grep(/^\d+$/, readdir(MAILDIR));
- closedir(MAILDIR);
- foreach (@files) {
- $mesgfile = "${mbox}${DIRSEP}${_}";
- if (!open(FILE, $mesgfile)) {
- warn "\nWarning: Unable to open message $mesgfile\n";
- next;
- }
- print STDOUT "." unless $QUIET;
- $mesg = '';
- ($index,$from,$date,$sub,$header) =
- &read_mail_header(FILE, *mesg, *fields);
-
- # Process message if valid
- if ($index ne '') {
- ($From{$index},$Date{$index},$Subject{$index}) =
- ($from,$date,$sub);
- $MsgHead{$index} = $mesg;
- $MsgHead{$index} .= "<HR>\n" unless $mesg =~ /^\s*$/;
-
- if ($ADD && !$SLOW) { $AddIndex{$index} = 1; }
- $IndexNum{$index} = &getNewMsgNum();
-
- $Message{$index} = &read_mail_body(
- FILE,
- $index,
- $header,
- *fields);
- # Check if conserving memory
- if ($SLOW) {
- &output_mail($index, 0, 0, *bogus, 1, 1);
- $Update{$IndexNum{$index}} = 1;
- undef $MsgHead{$index};
- undef $Message{$index};
- }
- }
- close(FILE);
- }
- } else { # UUCP mail box file
- if (!open(FILE, $mbox)) {
- warn "\nWarning: Unable to open $mbox\n";
- next;
- }
- $MBOX = 1; $MH = 0;
- print STDOUT "\nReading $mbox " unless $QUIET;
- while (<FILE>) { last if /$FROM/o; }
- MBOX: while (!eof(FILE)) {
- print STDOUT "." unless $QUIET;
- $mesg = '';
- ($index,$from,$date,$sub,$header) =
- &read_mail_header(FILE, *mesg, *fields);
-
- if ($index ne '') {
- ($From{$index},$Date{$index},$Subject{$index}) =
- ($from,$date,$sub);
- $MsgHead{$index} = $mesg;
- $MsgHead{$index} .= "<HR>\n" unless $mesg =~ /^\s*$/;
-
- if ($ADD && !$SLOW) { $AddIndex{$index} = 1; }
- $IndexNum{$index} = &getNewMsgNum();
-
- $Message{$index} = &read_mail_body(
- FILE,
- $index,
- $header,
- *fields);
- if ($SLOW) {
- &output_mail($index, 0, 0, *bogus, 1, 1);
- $Update{$IndexNum{$index}} = 1;
- undef $MsgHead{$index};
- undef $Message{$index};
- }
- } else {
- &read_mail_body(FILE, $index, $header, *fields, 1);
- }
- }
- close(FILE);
- }
- }
- }
-
- ## Check if there are any new messages
- if (!$EDITIDX && !$IDXONLY && $i == $NumOfMsgs) {
- print STDOUT "\nNo new messages\n" unless $QUIET;
- &quit(0);
- }
-
- ##---------------------------------------------##
- ## Setup data structures for final HTML output ##
- ##---------------------------------------------##
-
- ## Remove old message if hit maximum size
- if (!$IDXONLY && $MAXSIZE && ($NumOfMsgs > $MAXSIZE)) {
- if ($REVSORT) {
- @array = reverse &sort_messages();
- } else {
- @array = &sort_messages();
- }
- &ign_signals(); # Ignore termination signals
- while ($NumOfMsgs > $MAXSIZE) {
- $index = shift @array;
- &delmsg($index);
- $Update{$IndexNum{$array[0]}} = 1; # Update next
- foreach (split(/$bs/o, $FollowOld{$index})) { # Update any replies
- $Update{$IndexNum{$_}} = 1;
- }
- }
- }
- @array = &sort_messages();
-
- ## Compute follow up messages
- foreach $index (@array) {
- $FolCnt{$index} = 0 unless $FolCnt{$index};
- if (@array2 = split(/$'X/o, $Refs{$index})) {
- $tmp2 = $array2[$#array2];
- next unless defined($IndexNum{$MsgId{$tmp2}});
- $tmp = $MsgId{$tmp2};
- if ($Follow{$tmp}) { $Follow{$tmp} .= $bs . $index; }
- else { $Follow{$tmp} = $index; }
- $FolCnt{$tmp}++;
- }
- }
-
- ## Check for which messages to update when adding to archive
- if (!$IDXONLY && $ADD) {
- if ($UPDATE_ALL) {
- foreach $index (@array) { $Update{$IndexNum{$index}} = 1; }
- } else {
- $i = 0;
- foreach $index (@array) {
- ## Check for New follow-up links
- if ($FollowOld{$index} ne $Follow{$index}) {
- $Update{$IndexNum{$index}} = 1;
- }
- ## Check if new message; must update links in prev/next mesgs
- if ($AddIndex{$index}) {
- $Update{$IndexNum{$array[$i-1]}} = 1 if $i > 0;
- $Update{$IndexNum{$array[$i+1]}} = 1 if $i < $#array;
- }
- ## Check for New reference links
- foreach (split(/$'X/o, $Refs{$index})) {
- $tmp = $MsgId{$_};
- if (defined($IndexNum{$tmp}) && $AddIndex{$tmp}) {
- $Update{$IndexNum{$index}} = 1;
- }
- }
- $i++;
- }
- }
- }
-
- ##------------##
- ## Write HTML ##
- ##------------##
- &ign_signals(); # Ignore termination signals
- print STDOUT "\n" unless $QUIET;
- if (!$IDXONLY) {
- &write_mail(*array);
- &write_main_index();
- &write_thread_index() if $THREAD;
- } elsif ($THREAD) {
- &write_thread_index();
- } else {
- &write_main_index();
- }
-
- ## Save archive state
- if (!$IDXONLY) {
- &output_db();
- foreach $tmp (@OtherIdxs) {
- $THREAD = 0;
- $tmp = "${OUTDIR}${DIRSEP}$tmp"
- unless ($tmp =~ m%^/%) || (-e $tmp);
- if (&read_fmt_file($tmp)) {
- if ($THREAD) {
- $TIDXPATHNAME = "${OUTDIR}${DIRSEP}${TIDXNAME}";
- &write_thread_index();
- } else {
- $IDXPATHNAME = "${OUTDIR}${DIRSEP}${IDXNAME}";
- &write_main_index();
- }
- }
- }
- print STDOUT "$NumOfMsgs messages\n" unless $QUIET;
- }
-
- &quit(0);
- }
- ##---------------------------------------------------------------------------
- ## Function to do scan feature.
- ##
- sub scan {
- local($key, $num, $index, $day, $mon, $year, $from, $date,
- $subject, $time, @array);
-
- print STDOUT "$NumOfMsgs messages in $OUTDIR:\n\n";
- print STDOUT sprintf("%5s %s %-15s %-45s\n",
- "Msg #", "YY/MM/DD", "From", "Subject");
- print STDOUT sprintf("%5s %s %-15s %-45s\n",
- "-" x 5, "--------", "-" x 15, "-" x 45);
-
- @array = &sort_messages();
- foreach $index (@array) {
- $date = &time2mmddyy((split(/$X/o, $index))[0], 'yymmdd');
- $num = $IndexNum{$index};
- $from = substr(&dehtmlize(&extract_email_name($From{$index})), 0, 15);
- $subject = substr(&dehtmlize($Subject{$index}), 0, 45);
- print STDOUT sprintf("%5d %s %-15s %-45s\n",
- $num, $date, $from, $subject);
- }
- }
- ##---------------------------------------------------------------------------
- ## Routine to perform conversion of a single mail message to
- ## HTML.
- ##
- sub single {
- local($mhead,$index,$from,$date,$sub,$header,$handle,$mesg,
- $template,$filename,%fields);
-
- ## Prevent any verbose output
- $QUIET = 1;
-
- ## See where input is coming from
- if ($ARGV[0]) {
- open(SINGLE, $ARGV[0]) || &error("ERROR: Unable to open $ARGV[0]");
- $handle = 'SINGLE';
- $filename = $ARGV[0];
- } else {
- $handle = 'STDIN';
- }
-
- ## Read header
- ($index,$from,$date,$sub,$header) =
- &read_mail_header($handle, *mhead, *fields);
-
- ($From{$index},$Date{$index},$Subject{$index}) = ($from,$date,$sub);
-
- ## Read rest of message
- $mesg = &read_mail_body($handle, $index, $header, *fields);
-
- ## Output to stdout
- $template = $MSGPGBEG;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print STDOUT $template;
-
- $template = $MSGHEAD;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print STDOUT $template;
-
- print STDOUT "<H1>$sub</H1>\n",
- "<HR>\n",
- $mhead;
-
- print STDOUT "<HR>\n" unless $mhead =~ /^\s*$/;
- print STDOUT $mesg,
- "<HR>\n";
-
- $template = $MSGFOOT;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print STDOUT $template;
-
- $template = $MSGPGEND;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print STDOUT $template;
- }
- ##---------------------------------------------------------------------------
- ## Function for removing messages. *numbers points to an array
- ## of message numbers to delete
- ##
- sub rmm {
- local(*numbers) = shift;
- local($key, %Num2Index, $num, $didrmm, $filename);
-
- if ($#numbers < 0) {
- &error("Error: No message numbers specified");
- }
- $didrmm = 0;
-
- ## Make assoc arrays to perform deletions
- foreach $key (keys %IndexNum) {
- $Num2Index{$IndexNum{$key}} = $key;
- }
- ## Remove messages
- foreach $num (@numbers) {
- if ($num !~ /^\d+$/) {
- print STDERR "`$num' is not a legal message number\n";
- }
- if ($key = $Num2Index{$num}) {
- print STDOUT "\tRemoving message $num\n" unless $QUIET;
- &delmsg($key);
- $didrmm = 1;
- } else {
- print STDOUT "\tMessage $num does not exist\n" unless $QUIET;
- }
- }
- if (!$didrmm) {
- &error("ERROR: Messages specified do not exist");
- }
- }
- ##---------------------------------------------------------------------------
- sub delmsg {
- local($key) = @_;
- local($filename);
-
- &defineIndex2MsgId();
- $msgnum = $IndexNum{$key}; return 0 if ($msgnum eq '');
- $filename = $OUTDIR . $DIRSEP . &msgnum_filename($msgnum);
- delete $ContentType{$key};
- delete $Date{$key};
- delete $From{$key};
- delete $IndexNum{$key};
- delete $Refs{$key};
- delete $Subject{$key};
- delete $MsgId{$Index2MsgId{$key}};
- unlink $filename;
- foreach $filename (split(/$'X/o, $Derived{$key})) {
- unlink "${OUTDIR}${DIRSEP}${filename}";
- }
- delete $Derived{$key};
- $NumOfMsgs--;
- 1;
- }
- ##---------------------------------------------------------------------------
- ## write_mail outputs converted mail. It takes a reference to an
- ## array containing indexes of messages to output.
- ##
- sub write_mail {
- local(*idxarray) = $_[0];
- local($max, $hack) = ($#idxarray, 0);
- print STDOUT "Writing mail ...\n" unless $QUIET;
- if ($SLOW && !$ADD) { $ADD = 1; $hack = 1; }
- $i = 0;
- foreach $index (@idxarray) {
- &output_mail($index, $i, $max, *idxarray, $AddIndex{$index}, 0);
- $i++;
- }
- if ($hack) { $ADD = 0; }
- }
- ##---------------------------------------------------------------------------
- ## write_main_index outputs main index of archive
- ##
- sub write_main_index {
- local(@array) = &sort_messages();
- local($outhandle, $i, $i_p0, $filename, $tmpl);
-
- ## Set messages that are shown in index
- if ($IDXSIZE && (($i = ($#array+1) - $IDXSIZE) > 0)) {
- if ($REVSORT) {
- splice(@array, $IDXSIZE);
- } else {
- splice(@array, 0, $i);
- }
- }
-
- ## Open/create index file
- if ($ADD) {
- if (-e $IDXPATHNAME) {
- &cp($IDXPATHNAME, "${OUTDIR}${DIRSEP}tmp.$$");
- open(MAILLISTIN, "${OUTDIR}${DIRSEP}tmp.$$")
- || &error("ERROR: Unable to open ${OUTDIR}${DIRSEP}tmp.$$");
- $MLCP = 1;
- } else {
- $MLCP = 0;
- }
- }
- if ($IDXONLY) {
- $outhandle = STDOUT;
- } else {
- open(MAILLIST, "> $IDXPATHNAME") ||
- &error("ERROR: Unable to create $IDXPATHNAME");
- $outhandle = 'MAILLIST';
- }
- print STDOUT "Writing $IDXPATHNAME ...\n" unless $QUIET;
-
- ## Print top part of index
- &output_maillist_head($outhandle, MAILLISTIN);
-
- ## Output messages to HTML
- $i = 0;
- foreach $index (@array) {
- $msgnum = $IndexNum{$index};
- $i_p0 = &fmt_msgnum($msgnum); # Var for replace_li_var
- $filename = &msgnum_filename($msgnum); # Var for replace_li_var
- $tmpl = $LITMPL;
- $tmpl =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $outhandle $tmpl;
- $i++;
- }
-
- ## Print bottom part of index
- &output_maillist_foot($outhandle, MAILLISTIN);
- close($outhandle) unless $IDXONLY;
- close(MAILLISTIN), unlink("${OUTDIR}${DIRSEP}tmp.$$") if $MLCP;
- }
- ##---------------------------------------------------------------------------
- ## write_thread_index outputs the thread index
- ##
- sub write_thread_index {
- local($tmpl, $handle);
-
- if ($IDXONLY) {
- $handle = 'STDOUT';
- } else {
- open(THREAD, "> $TIDXPATHNAME") ||
- &error("ERROR: Unable to create $TIDXPATHNAME");
- $handle = 'THREAD';
- }
- print STDOUT "Writing $TIDXPATHNAME ...\n" unless $QUIET;
-
- $tmpl = $TIDXPGBEG;
- $tmpl =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmpl;
-
- $tmpl = $THEAD;
- $tmpl =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmpl;
-
- &output_thread_index($handle);
-
- $tmpl = $TFOOT;
- $tmpl =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmpl;
-
- &output_doclink($handle);
-
- $tmpl = $TIDXPGEND;
- $tmpl =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmpl;
-
- close($handle) unless $IDXONLY;
- }
- ##---------------------------------------------------------------------------
- ## read_mail_header() is responsible for parsing the header of
- ## a mail message.
- ##
- sub read_mail_header {
- local($handle, *mesg, *fields) = @_;
- local(%l2o, $header, $index, $from, $sub, $date, $tmp, $msgid,
- @refs, @array);
-
- $header = &'MAILread_file_header("main'$handle", *fields, *l2o);
-
- ##------------##
- ## Get Msg-ID ##
- ##------------##
- $msgid = $fields{'message-id'} || $fields{'msg-id'} ||
- $fields{'content-id'};
- if (!($msgid =~ s/\s*<([^>]*)>\s*/$1/g)) {
- $msgid =~ s/^\s*//;
- $msgid =~ s/\s*$//;
- }
-
- # Return if message already exists in archive
- #
- if ($msgid && defined($MsgId{$msgid})) {
- return ("", "", "", "", "");
- }
-
- ##----------##
- ## Get date ##
- ##----------##
- $date = '';
- if ($fields{'received'}) {
- @array = split(/$'FieldSep/o, $fields{'received'});
- $tmp = shift @array;
- @array = split(/;/, $tmp);
- $date = pop @array;
- } elsif ($fields{'date'}) {
- @array = split(/$'FieldSep/o, $fields{'date'});
- $date = shift @array;
- }
- if ($date =~ /\w/) {
- local($wday, $mday, $mon, $yr, $hr, $min, $sec, $zone) =
- &parse_date($date);
- if ($zone) {
- $index = &timegm($sec,$min,$hr,$mday,$mon,
- ($yr > 1900 ? $yr-1900 : $yr));
- } else {
- $index = &timelocal($sec,$min,$hr,$mday,$mon,
- ($yr > 1900 ? $yr-1900 : $yr));
- }
-
- ## Try to modify time/date based on timezone ##
- if ($zone =~ /^[\+-]\d+$/) {# Numeric timezone
- $zone =~ s/0//g;
- $index -= ($zone*3600);
- } else { # Timezone abbrev
- warn qq|Warning: Undefined time zone: "$zone", Line $.\n|
- if $zone && !defined($Zone{$zone});
- $index += ($Zone{$zone}*3600); # %Zone defined above
- }
- } else {
- warn "Warning: Could not find date for message\n";
- $date = ''; $index = 0;
- }
- ##-------------##
- ## Get Subject ##
- ##-------------##
- if ($fields{'subject'} !~ /^\s*$/) {
- ($sub = $fields{'subject'}) =~ s/\s*$//;
- &htmlize(*sub);
- } else {
- $sub = 'No Subject';
- }
- ##----------##
- ## Get From ##
- ##----------##
- $tmp = $fields{'from'} || $fields{'apparently-from'};
- $from = &convert_line($tmp);
- ##----------------##
- ## Get References ##
- ##----------------##
- $tmp = $fields{'references'};
- while ($tmp =~ s/<([^>]+)>//) {
- push(@refs, $1);
- }
- $tmp = $fields{'in-reply-to'};
- if ($tmp =~ s/^[^<]*<([^>]*)>.*$/$1/) {
- push(@refs, $tmp) unless $tmp =~ /^\s*$/;
- }
- ##------------------------##
- ## Create HTML for header ##
- ##------------------------##
- $mesg .= &htmlize_header(*fields, *l2o);
-
- ## Insure uniqueness of msg-id
- $index .= $'X . sprintf("%d",$LastMsgNum+1);
-
- if ($fields{'content-type'}) {
- ($tmp = $fields{'content-type'}) =~ m%^\s*([\w-/]+)%;
- $tmp = $1 || 'text/plain';
- $tmp =~ tr/A-Z/a-z/;
- } else {
- $tmp = 'text/plain';
- }
- $ContentType{$index} = $tmp;
-
- $MsgId{$msgid} = $index;
- &remove_dups(*refs); # Remove duplicate msg-ids
- $Refs{$index} = join($'X, @refs) if (@refs);
-
- ($index,$from,$date,$sub,$header);
- }
- ##---------------------------------------------------------------------------
- ## read_mail_body() reads in the body of a message. The returned
- ## filtered body is in $ret.
- ##
- sub read_mail_body {
- local($handle, $index, $header, *fields, $skip) = @_;
- local($ret, $data, @files);
-
- while (<$handle>) {
- last if $MBOX && /$FROM/o;
- $data .= $_;
- }
- return '' if $skip;
- $fields{'content-type'} = 'text/plain'
- if $fields{'content-type'} =~ /^\s*$/;
- ($ret, @files) = &'MAILread_body($header, $data,
- $fields{'content-type'},
- $fields{'content-transfer-encoding'});
- $ret = join('',
- "<DL>\n",
- "<DT><STRONG>Warning</STRONG></DT>\n",
- "<DD>Could not process message with given Content-Type: \n",
- "<CODE>", $fields{'content-type'}, "</CODE>\n",
- "</DD>\n",
- "</DL>\n"
- ) unless $ret;
- if (@files) {
- $Derived{$index} = join($'X, @files);
- }
- $ret;
- }
- ##---------------------------------------------------------------------------
- ## Output/edit a mail message.
- ## $index => current index (== $array[$i])
- ## $i => current index into *array
- ## $maxnum => size of *array
- ## *array => reference to array of indexes
- ## $force => flag if mail is written and not editted, regardless
- ## $nocustom => ignore sections with user customization
- ## ($i, $maxnum, *array ignored if true)
- ##
- sub output_mail {
- local($index, $i, $maxnum, *array, $force, $nocustom) = @_;
- local($msgi,$tmp,$tmp2,$template,@array2);
- local($filepathname, $tmppathname);
- local($adding) = ($ADD && !$force);
-
- # Variables for replace_li_var
- local($i_p0,$i_p1,$i_m1,$filename,$nextindex,$previndex);
-
- if (!$nocustom) {
- $nextindex = $array[$i+1];
- $previndex = $array[$i-1];
- }
-
- # Here $i is the current message count and not necessarily the
- # message number in the filename.
-
- $i_p0 = &fmt_msgnum($IndexNum{$index});
- if (!$nocustom) {
- $i_p1 = &fmt_msgnum($IndexNum{$nextindex});
- $i_m1 = &fmt_msgnum($IndexNum{$previndex});
- }
-
- $filename = &msgnum_filename($IndexNum{$index});
- $filepathname = $OUTDIR . $DIRSEP . $filename;
- $tmppathname = $OUTDIR . $DIRSEP . "msgtmp.$$";
-
- if ($adding) {
- return ($i_p0,$filename) unless $Update{$IndexNum{$index}};
- &cp($filepathname, $tmppathname);
- open(MSGFILEIN, $tmppathname)
- || &error("ERROR: Unable to open $tmppathname");
- }
- open(MSGFILE, "> $filepathname")
- || &error("ERROR: Unable to create $filepathname");
-
- ## Output HTML header
- if ($adding) {
- while (<MSGFILEIN>) { last if /<!--X-Body-Begin/; }
- }
- if (!$nocustom) {
- &defineIndex2MsgId();
- print MSGFILE "<!--X-Subject: $Subject{$index} -->\n",
- "<!--X-From: $From{$index} -->\n",
- "<!--X-Date: $Date{$index} -->\n",
- "<!--X-Message-Id: $Index2MsgId{$index} -->\n",
- "<!--X-ContentType: $ContentType{$index} -->\n",
- "<!--X-Head-End-->\n";
- $template = $MSGPGBEG;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print MSGFILE $template;
- }
- print MSGFILE "<!--X-Body-Begin-->\n";
-
- ## Output header
- if ($adding) {
- while (<MSGFILEIN>) {
- last if /<!--X-User-Header-End/ || /<!--X-TopPNI--/;
- }
- }
- print MSGFILE "<!--X-User-Header-->\n";
- if (!$nocustom) {
- $template = $MSGHEAD;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print MSGFILE $template;
- }
- print MSGFILE "<!--X-User-Header-End-->\n";
-
- ## Output Prev/Next/Index links at top
- if ($adding) {
- while (<MSGFILEIN>) { last if /<!--X-TopPNI-End/; }
- }
- print MSGFILE "<!--X-TopPNI-->\n";
- if (!$nocustom) {
- $template = $TOPLINKS;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print MSGFILE $template;
- }
- print MSGFILE qq|\n|;
- print MSGFILE "<!--X-TopPNI-End-->\n";
-
- ## Output message body
- if ($adding) {
- $tmp2 = '';
- while (<MSGFILEIN>) {
- $tmp2 .= $_;
- last if /<!--X-MsgBody-End/;
- }
- foreach (split(/$'X/o, $Refs{$index})) {# Convert msg-ids to hyperlinks
- ($tmp = $_) =~ s/(\W)/\\$1/g;
- if (defined($IndexNum{$MsgId{$_}}) &&
- $IndexNum{$MsgId{$_}} != $IndexNum{$index}) {
- $msgi = &fmt_msgnum($IndexNum{$MsgId{$_}});
- $tmp2 =~ s/$tmp/<A HREF="msg$msgi.html">$_<\/A>/g;
- }
- }
- print MSGFILE $tmp2;
- } else {
- print MSGFILE "<!--X-MsgBody-->\n";
- print MSGFILE "<H1>", $Subject{$index}, "</H1>\n";
- print MSGFILE "<HR>\n";
- foreach (split(/$'X/o, $Refs{$index})) {# Convert msg-ids to hyperlinks
- ($tmp = $_) =~ s/(\W)/\\$1/g;
- if (defined($IndexNum{$MsgId{$_}}) &&
- $IndexNum{$MsgId{$_}} != $IndexNum{$index}) {
-
- $msgi = &fmt_msgnum($IndexNum{$MsgId{$_}});
- $MsgHead{$index} =~
- s/$tmp/<A HREF="msg$msgi.html">$_<\/A>/g;
- $Message{$index} =~
- s/$tmp/<A HREF="msg$msgi.html">$_<\/A>/g;
- }
- }
-
- print MSGFILE $MsgHead{$index};
- print MSGFILE $Message{$index};
- print MSGFILE "<!--X-MsgBody-End-->\n";
- }
-
- ## Output any followup messages
- if ($adding) {
- while (<MSGFILEIN>) { last if /<!--X-Follow-Ups-End/; }
- }
- print MSGFILE "<!--X-Follow-Ups-->\n";
- if (!$nocustom) {
- @array2 = split(/$bs/o, $Follow{$index});
- if ($#array2 >= 0) {
- $tmp = 1; # Here, $tmp a flag if <HR> printed
- print MSGFILE "<HR>\n",
- "<STRONG>Follow-Ups</STRONG>:\n",
- "<UL>\n";
- foreach (@array2) {
- print MSGFILE "<LI>",
- qq|<STRONG><A HREF="|, &msgnum_filename($IndexNum{$_}),
- qq|">$Subject{$_}</A></STRONG></LI>\n|,
- "<UL>\n",
- "<LI><EM>From</EM>: $From{$_}</LI>\n",
- "</UL>\n";
- }
- print MSGFILE "</UL>\n";
- } else {
- $tmp = 0;
- }
- }
- print MSGFILE "<!--X-Follow-Ups-End-->\n";
-
- ## Output any references
- if ($adding) {
- while (<MSGFILEIN>) { last if /<!--X-References-End/; }
- }
- print MSGFILE "<!--X-References-->\n";
- if (!$nocustom) {
- @array2 = split(/$'X/o, $Refs{$index}); $tmp2 = 0;
- if ($#array2 >= 0) {
- foreach (@array2) {
- if (defined($IndexNum{$MsgId{$_}})) {
- if (!$tmp) { print MSGFILE "<HR>\n"; $tmp = 1; }
- if (!$tmp2) {
- print MSGFILE "<STRONG>References</STRONG>:\n",
- "<UL>\n";
- $tmp2 = 1;
- }
- print MSGFILE "<LI>",
- qq|<STRONG><A HREF="|,
- &msgnum_filename($IndexNum{$MsgId{$_}}),
- qq|">$Subject{$MsgId{$_}}</A></STRONG></LI>\n|,
- "<UL>\n",
- "<LI><EM>From</EM>: $From{$MsgId{$_}}</LI>\n",
- "</UL>\n";
- }
- }
- print MSGFILE "</UL>\n" if $tmp2;
- }
- }
- print MSGFILE "<!--X-References-End-->\n";
-
- ## Output verbose links to prev/next message in list
- if ($adding) {
- while (<MSGFILEIN>) { last if /<!--X-BotPNI-End/; }
- }
- print MSGFILE "<!--X-BotPNI-->\n";
- if (!$nocustom) {
- $template = $BOTLINKS;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print MSGFILE $template;
- print MSGFILE qq|\n|;
- }
- print MSGFILE "<!--X-BotPNI-End-->\n";
-
- ## Output footer
- if ($adding) {
- while (<MSGFILEIN>) {
- last if /<!--X-User-Footer-End/;
- }
- }
- print MSGFILE "<!--X-User-Footer-->\n";
- if (!$nocustom) {
- $template = $MSGFOOT;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print MSGFILE $template;
- }
- print MSGFILE "<!--X-User-Footer-End-->\n";
-
- if (!$nocustom) {
- $template = $MSGPGEND;
- $template =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print MSGFILE $template;
- }
-
- close(MSGFILE);
- close(MSGFILEIN), unlink($tmppathname) if ($adding);
-
- ($i_p0, $filename);
- }
- ##---------------------------------------------------------------------------
- ## output_maillist_head() outputs the beginning of the index page.
- ##
- sub output_maillist_head {
- local($handle, $cphandle) = @_;
- local($tmp);
-
- ## Output title
- $tmp = $IDXPGBEG;
- $tmp =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmp;
- print $handle "<!--X-ML-Title-H1-End-->\n";
-
- if ($MLCP) {
- while (<$cphandle>) { last if /<!--X-ML-Title-H1-End/; }
- }
-
- ## Output header file
- if ($HEADER) { # Read external header
- print $handle "<!--X-ML-Header-->\n";
- if (open(HEADER, $HEADER)) {
- print $handle <HEADER>;
- } else {
- warn "Warning: Unable to open header: $HEADER\n";
- }
- if ($MLCP) {
- while (<$cphandle>) { last if /<!--X-ML-Header-End/; }
- }
- print $handle "<!--X-ML-Header-End-->\n";
- } elsif ($MLCP) { # Preserve maillist header
- while (<$cphandle>) {
- print $handle $_;
- last if /<!--X-ML-Header-End/;
- }
- } else { # No header
- print $handle "<!--X-ML-Header-->\n",
- "<!--X-ML-Header-End-->\n";
- }
-
- print $handle "<!--X-ML-Index-->\n";
- $tmp = $LIBEG;
- $tmp =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmp;
- }
- ##---------------------------------------------------------------------------
- ## output_maillist_foot() outputs the end of the index page.
- ##
- sub output_maillist_foot {
- local($handle, $cphandle) = @_;
- local($tmp);
-
- $tmp = $LIEND;
- $tmp =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmp;
- print $handle "<!--X-ML-Index-End-->\n";
-
- ## Skip past index in old maillist file
- if ($MLCP) {
- while (<$cphandle>) { last if /<!--X-ML-Index-End/; }
- }
-
- ## Output footer file
- if ($FOOTER) { # Read external footer
- print $handle "<!--X-ML-Footer-->\n";
- if (open(FOOTER, $FOOTER)) {
- print $handle <FOOTER>;
- } else {
- warn "Warning: Unable to open footer: $FOOTER\n";
- }
- if ($MLCP) {
- while (<$cphandle>) { last if /<!--X-ML-Footer-End/; }
- }
- print $handle "<!--X-ML-Footer-End-->\n";
- } elsif ($MLCP) { # Preserve maillist footer
- while (<$cphandle>) {
- print $handle $_;
- last if /<!--X-ML-Footer-End/;
- }
- } else { # No footer
- print $handle "<!--X-ML-Footer-->\n",
- "<!--X-ML-Footer-End-->\n";
- }
-
- &output_doclink($handle);
-
- ## Close document
- $tmp = $IDXPGEND;
- $tmp =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle $tmp;
- }
- ##---------------------------------------------------------------------------
- ## Output link to documentation, if specified
- ##
- sub output_doclink {
- local($handle) = ($_[0]);
- if (!$NODOC && $DOCURL) {
- print $handle "<HR>\n";
- print $handle
- "<ADDRESS>\n",
- "Mail converted by ",
- qq|<A HREF="$DOCURL"><CODE>MHonArc</CODE></A> $VERSION\n|,
- "</ADDRESS>\n";
- }
- }
- #############################################################################
- ## Miscellaneous routines
- #############################################################################
- ##---------------------------------------------------------------------------
- sub getNewMsgNum {
- $NumOfMsgs++; $LastMsgNum++;
- $LastMsgNum;
- }
- ##---------------------------------------------------------------------------
- ## replace_li_var() is used to substitute vars to current
- ## values. This routine relies on dynamic linking for $i,
- ## $i_{p0,p1,m1}, $index, $maxnum and $filename.
- ##
- sub replace_li_var {
- local($val) = $_[0];
- local($var,$len,$canclip,$raw,$isurl,$tmp,$ret) = ('',0,0,0,0,'','');
- local($expand) = (0);
-
- ## Get length specifier (if defined)
- ($var, $len) = split(/:/, $val, 2);
-
- ## Check if variable in a URL string
- $isurl = 1 if ($len =~ s/u//ig);
-
- REPLACESW: {
- if ($var eq 'SUBJECT') {
- $canclip = 1; $raw = 1; $isurl = 0;
- $tmp = &dehtmlize($Subject{$index});
- last REPLACESW;
- }
- if ($var eq 'SUBJECTNA') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize($Subject{$index});
- last REPLACESW;
- }
- if ($var eq 'A_ATTR') {
- $isurl = 0; $tmp = qq|NAME="$i_p0" HREF="$filename"|;
- last REPLACESW;
- }
- if ($var eq 'A_NAME')
- { $isurl = 0; $tmp = qq|NAME="$i_p0"|; last REPLACESW; }
- if ($var eq 'A_HREF')
- { $isurl = 0; $tmp = qq|HREF="$filename"|; last REPLACESW; }
- if ($var eq 'DATE')
- { $tmp = $Date{$index}; last REPLACESW; }
- if ($var eq 'DDMMYY') {
- $tmp = &time2mmddyy((split(/$X/o, $index))[0], 'ddmmyy');
- last REPLACESW;
- }
- if ($var eq 'DOCURL')
- { $isurl = 0; $tmp = $DOCURL; last REPLACESW; }
- if ($var eq 'FROM') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize($From{$index});
- last REPLACESW;
- }
- if ($var eq 'FROMADDR') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize(&extract_email_address($From{$index}));
- last REPLACESW;
- }
- if ($var eq 'FROMNAME') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize(&extract_email_name($From{$index}));
- last REPLACESW;
- }
- if ($var eq 'GMTDATE')
- { $tmp = $curdate; last REPLACESW; }
- if ($var eq 'ICON') {
- if ($Icons{$ContentType{$index}}) {
- $tmp = qq|<IMG SRC="$Icons{$ContentType{$index}}" | .
- qq|ALT="[$ContentType{$index}]">|;
- } else {
- $tmp = qq|<IMG SRC="$Icons{'unknown'}" ALT="[unknown]">|;
- }
- last REPLACESW;
- }
- if ($var eq 'ICONURL') {
- $isurl = 0;
- if ($Icons{$ContentType{$index}}) {
- $tmp = $Icons{$ContentType{$index}};
- } else {
- $tmp = $Icons{'unknown'};
- }
- last REPLACESW;
- }
- if ($var eq 'IDXFNAME')
- { $tmp = $IDXNAME; last REPLACESW; }
- if ($var eq 'IDXSIZE')
- { $tmp = $IDXSIZE; last REPLACESW; }
- if ($var eq 'IDXTITLE')
- { $canclip = 1; $tmp = $TITLE; last REPLACESW; }
- if ($var eq 'LOCALDATE')
- { $tmp = $locdate; last REPLACESW; }
- if ($var eq 'MMDDYY') {
- $tmp = &time2mmddyy((split(/$X/o, $index))[0], 'mmddyy');
- last REPLACESW;
- }
- if ($var eq 'MSGID') {
- &defineIndex2MsgId();
- $tmp = $Index2MsgId{$index};
- last REPLACESW;
- }
- if ($var eq 'MSGNUM')
- { $tmp = $i_p0; last REPLACESW; }
- if ($var eq 'NEXTFROM') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize($From{$nextindex});
- last REPLACESW;
- }
- if ($var eq 'NEXTFROMADDR') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize(&extract_email_address($From{$nextindex}));
- last REPLACESW;
- }
- if ($var eq 'NEXTFROMNAME') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize(&extract_email_name($From{$nextindex}));
- last REPLACESW;
- }
- if ($var eq 'NEXTMSG')
- { $tmp = "msg${i_p1}.html"; last REPLACESW; }
- if ($var eq 'NEXTMSGNUM')
- { $tmp = $i_p1; last REPLACESW; }
- if ($var eq 'NEXTSUBJECT') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize($Subject{$nextindex});
- last REPLACESW;
- }
- if ($var eq 'NUMFOLUP')
- { $tmp = $FolCnt{$index}; last REPLACESW; }
- if ($var eq 'NUMOFIDXMSG') {
- $tmp = ($NumOfMsgs > $IDXSIZE ? $IDXSIZE : $NumOfMsgs);
- last REPLACESW;
- }
- if ($var eq 'NUMOFMSG')
- { $tmp = $NumOfMsgs; last REPLACESW; }
- if ($var eq 'ORDNUM')
- { $tmp = $i+1; last REPLACESW; }
- if ($var eq 'OUTDIR')
- { $tmp = $OUTDIR; last REPLACESW; }
- if ($var eq 'PREVFROM') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize($From{$previndex});
- last REPLACESW;
- }
- if ($var eq 'PREVFROMADDR') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize(&extract_email_address($From{$previndex}));
- last REPLACESW;
- }
- if ($var eq 'PREVFROMNAME') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize(&extract_email_name($From{$previndex}));
- last REPLACESW;
- }
- if ($var eq 'PREVMSG')
- { $tmp = "msg${i_m1}.html"; last REPLACESW; }
- if ($var eq 'PREVMSGNUM')
- { $tmp = $i_m1; last REPLACESW; }
- if ($var eq 'PREVSUBJECT') {
- $canclip = 1; $raw = 1;
- $tmp = &dehtmlize($Subject{$previndex});
- last REPLACESW;
- }
- if ($var eq 'PROG')
- { $tmp = $PROG; last REPLACESW; }
- if ($var eq 'TIDXFNAME')
- { $tmp = $TIDXNAME; last REPLACESW; }
- if ($var eq 'TIDXTITLE')
- { $canclip = 1; $tmp = $TTITLE; last REPLACESW; }
- if ($var eq 'VERSION')
- { $tmp = $VERSION; last REPLACESW; }
- if ($var eq '')
- { $tmp = '$'; last REPLACESW; }
- if ($var eq 'NEXTBUTTON') {
- $expand = 1;
- $tmp = (($i < $maxnum) ? $NEXTBUTTON : $NEXTBUTTONIA);
- last REPLACESW;
- }
- if ($var eq 'NEXTLINK') {
- $expand = 1;
- $tmp = (($i < $maxnum) ? $NEXTLINK : $NEXTLINKIA);
- last REPLACESW;
- }
- if ($var eq 'PREVBUTTON') {
- $expand = 1;
- $tmp = (($i > 0) ? $PREVBUTTON : $PREVBUTTONIA);
- last REPLACESW;
- }
- if ($var eq 'PREVLINK') {
- $expand = 1;
- $tmp = (($i > 0) ? $PREVLINK : $PREVLINKIA);
- last REPLACESW;
- }
- if ($var eq 'YYMMDD') {
- $tmp = &time2mmddyy((split(/$X/o, $index))[0], 'yymmdd');
- last REPLACESW;
- }
- warn qq|Warning: Unrecognized variable: "$val"\n|;
- return '';
- }
-
- ## Check if string needs to expanded again
- if ($expand) {
- $tmp =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- }
-
- ## Check if clipping string
- if ($len > 0 && $canclip) {
- $ret = substr($tmp, 0, $len);
- } else {
- $ret = $tmp;
- }
-
- ## Check if URL text specifier is set
- if ($isurl) {
- $ret = &urlize($ret);
- } else {
- &htmlize(*ret) if $raw;
- }
-
- ## Check for subject link
- $ret = qq|<A NAME="$i_p0" HREF="$filename">$ret</A>| if $var eq 'SUBJECT';
-
- $ret;
- }
- ##---------------------------------------------------------------------------
- ## Add mailto URLs to $str.
- ##
- sub mailto {
- local(*str) = shift;
- if ($MAILTOURL) {
- $str =~ s|([\!\%\w\.\-+=]+@[\w\.\-]+)|&mailUrl($1)|ge;
- } else {
- $str =~ s|([\!\%\w\.\-+=]+@[\w\.\-]+)|<A HREF="mailto:$1">$1</A>|g;
- }
- }
- ##---------------------------------------------------------------------------
- ## $sub, $msgid, $from come from read_mail_header() (ugly!!!!)
- ##
- sub mailUrl {
- local($to) = (&urlize(shift));
- local($url) = ($MAILTOURL);
- local($subjectl, $froml, $msgidl) =
- (&urlize($sub), &urlize($from), &urlize($msgid));
- $url =~ s/\$FROM\$/$froml/g;
- $url =~ s/\$MSGID\$/$msgidl/g;
- $url =~ s/\$SUBJECT\$/$subjectl/g;
- $url =~ s/\$SUBJECTNA\$/$subjectl/g;
- $url =~ s/\$TO\$/$to/g;
- qq|<A HREF="$url">$to</A>|;
- }
- ##---------------------------------------------------------------------------
- sub newsurl {
- local(*str) = shift;
- local($h, @groups);
- $str =~ s/^([^:]*:\s*)//; $h = $1;
- $str =~ s/\s//g; # Strip whitespace
- @groups = split(/,/, $str); # Split groups
- foreach (@groups) { # Make hyperlinks
- s|(.*)|<A HREF="news:$1">$1</A>|;
- }
- $str = $h . join(', ', @groups); # Rejoin string
- }
- ##---------------------------------------------------------------------------
- sub get_header_tags {
- local($f) = shift;
- local($ftago, $ftagc, $tago, $tagc);
-
- ## Get user specified tags (this is one funcky looking code)
- $tag = (defined($HeadHeads{$f}) ?
- $HeadHeads{$f} : $HeadHeads{"-default-"});
- $ftag = (defined($HeadFields{$f}) ?
- $HeadFields{$f} : $HeadFields{"-default-"});
- if ($tag) { $tago = "<$tag>"; $tagc = "</$tag>"; }
- else { $tago = $tagc = ''; }
- if ($ftag) { $ftago = "<$ftag>"; $ftagc = "</$ftag>"; }
- else { $ftago = $ftagc = ''; }
-
- ($tago, $tagc, $ftago, $ftagc);
- }
- ##---------------------------------------------------------------------------
- sub field_add_links {
- local($label, *fld_text) = @_;
- &mailto(*fld_text)
- if !$NOMAILTO &&
- $label =~ /^(to|from|cc|sender|reply-to)/i;
- &newsurl(*fld_text)
- if !$NONEWS && $label =~ /^newsgroup/i;
-
- }
- ##---------------------------------------------------------------------------
- ## convert_line() translates a line to HTML. Checks are made for
- ## embedded URLs.
- ##
- sub convert_line {
- local($str) = $_[0];
- local($item, $item2, $item2h, @array);
-
- if (!$NOURL &&
- (@array = split(m%($Url[^\s\(\)\|<>"']*[^\.\?;,"'\|\[\]\(\)\s<>])%o,
- $str))
- ) {
- $str = '';
- while($#array > 0) {
- $item = &entify(shift @array); # Get non-URL text
- $item2 = shift @array; # Get URL
- $item2h = &entify($item2); # Variable for <A> content
-
- $str .= join('',
- $item,
- '<A HREF="', $item2, '">', $item2h, '</A>');
-
- # The next line is needed since Perl's split function also
- # returns extra entries for nested ()'s in the split pattern.
- shift @array if $array[0] =~ m%^$Url$%o;
- }
- $item = &entify(shift @array); # Last item in array
- $str .= $item;
- } else {
- &htmlize(*str);
- }
- $str;
- }
- ##---------------------------------------------------------------------------
- ## ign_signals() sets mhonarc to ignore termination signals. This
- ## routine is called right before an archive is written/editted to
- ## help prevent archive corruption.
- ##
- sub ign_signals {
- $SIG{'ABRT'} = 'IGNORE';
- $SIG{'HUP'} = 'IGNORE';
- $SIG{'INT'} = 'IGNORE';
- $SIG{'PIPE'} = 'IGNORE';
- $SIG{'QUIT'} = 'IGNORE';
- $SIG{'TERM'} = 'IGNORE';
- }
- ##---------------------------------------------------------------------------
- ## set_handler() sets up the quit() routine to be called when
- ## a termination signal is sent to mhonarc.
- sub set_handler {
- $SIG{'ABRT'} = 'quit';
- $SIG{'HUP'} = 'quit';
- $SIG{'INT'} = 'quit';
- $SIG{'PIPE'} = 'quit';
- $SIG{'QUIT'} = 'quit';
- $SIG{'TERM'} = 'quit';
- }
- ##---------------------------------------------------------------------------
- ## create_lock_file() creates a file with zero permissions to act
- ## as a lock. Thanks to Walter_Hobbs@rand.org (Walt Hobbs) for
- ## giving me a way to achieve this in Perl without possible race
- ## conditions or the use of syscall.
- ##
- ## Note: There is yet to be a way to a single locking capability
- ## that works across mutliple operating systems: Unix, DOS, etc.
- ##
- sub create_lock_file {
- local($file, $tries, $sleep, $force) = @_;
- local($umask, $ret);
- $ret = 0;
- eval '$umask = umask(0777)' if $UNIX;
- while ($tries > 0) {
- if (open(LCK_FILE, "> $file")) {
- $ISLOCK = 1;
- $ret = 1;
- last;
- }
- sleep($sleep) if $sleep > 0;
- $tries--;
- }
- if ($force) { # Set lock files if force option set
- $ISLOCK = 1; $ret = 1;
- }
- eval 'umask($umask)' if $UNIX;
- $ret;
- }
- ##---------------------------------------------------------------------------
- sub clean_up {
- if ($ISLOCK) {
- unlink ($LOCKFILE);
- $ISLOCK = 0;
- }
- }
- ##---------------------------------------------------------------------------
- sub error {
- &clean_up();
- die @_, "\n";
- }
- ##---------------------------------------------------------------------------
- sub quit {
- local($status) = shift;
- &clean_up();
- if ($TIME) {
- $EndTime = (times)[0];
- printf(STDERR "\nTime: %.4f CPU seconds\n", $EndTime - $StartTime);
- }
- exit $status;
- }
- ##---------------------------------------------------------------------------
- ## Create HTML for header
- sub htmlize_header {
- local(*fields, *l2o) = @_;
- local($tmp, $key, $tago, $tagc, $ftago, $ftagc, $mesg, $item, @array, %hf);
- %hf = %fields;
- foreach $item (@FieldOrder) {
- if ($item eq '-extra-') {
- foreach $key (sort keys %hf) {
- next if $FieldODefs{$key};
- delete $hf{$key}, next if &exclude_field($key);
-
- @array = split(/$'FieldSep/o, $hf{$key});
- foreach $tmp (@array) {
- $tmp = &convert_line($tmp);
- &field_add_links($key, *tmp);
- ($tago, $tagc, $ftago, $ftagc) = &get_header_tags($key);
- $mesg .= join('', "<LI>\n",
- $tago, $l2o{$key}, $tagc, ": ",
- $ftago, $tmp, $ftagc, "\n",
- "</LI>\n");
- }
- delete $hf{$key};
- }
- } else {
- if (!&exclude_field($item) && $hf{$item}) {
- @array = (split(/$'FieldSep/o, $hf{$item}));
- foreach $tmp (@array) {
- $tmp = &convert_line($tmp);
- &field_add_links($item, *tmp);
- ($tago, $tagc, $ftago, $ftagc) = &get_header_tags($item);
- $mesg .= join('', "<LI>\n",
- $tago, $l2o{$item}, $tagc, ": ",
- $ftago, $tmp, $ftagc, "\n",
- "</LI>\n");
- }
- }
- delete $hf{$item};
- }
- }
- if ($mesg) { $mesg = "<UL>\n" . $mesg . "</UL>\n"; }
- $mesg;
- }
- ##---------------------------------------------------------------------------
- sub output_thread_index {
- local($handle) = $_[0];
- local(%HasRef, %Replies, %Printed);
- local(@array, @refs);
- local($index, $msgid, $refindex, $level);
-
- ## Routine to print thread
- ##
- sub print_thread {
- local($i) = @_;
- local(@repls);
-
- &print_thread_entry($handle, $i);
- $Printed{$i} = 1;
- if (@repls = sort increase_index split(/$bs/o, $Replies{$i})) {
- $level++;
- print $handle "<UL>\n" if $level <= $TLEVELS;
- foreach (@repls) {
- &print_thread($_);
- }
- print $handle "</UL>\n" if $level <= $TLEVELS;
- $level--;
- }
- }
-
- ## Compute threads
- ##
- foreach $index (keys %Subject) {
- next unless $Refs{$index};
- @refs = split(/$X/o, $Refs{$index});
- $msgid = $refs[$#refs]; ## get last (rfc1036)
- if ($refindex = $MsgId{$msgid}) {
- $HasRef{$index} = 1;
- if ($Replies{$refindex}) {
- $Replies{$refindex} .= $bs . $index;
- } else {
- $Replies{$refindex} = $index;
- }
- }
- }
-
- ## Print index
- ##
- if ($TREVERSE) {
- @array = sort decrease_index keys %Subject;
- } else {
- @array = sort increase_index keys %Subject;
- }
- # Set messages that are shown in index
- if ($IDXSIZE && (($i = ($#array+1) - $IDXSIZE) > 0)) {
- if ($TREVERSE) {
- splice(@array, $IDXSIZE);
- } else {
- splice(@array, 0, $i);
- }
- }
- if ($TSUBSORT) {
- @array = sort increase_subject @array;
- }
- print $handle "<UL>\n";
- foreach $index (@array) {
- &print_thread($index) unless $Printed{$index} || $HasRef{$index};
- }
- print $handle "</UL>\n";
- }
- ##---------------------------------------------------------------------------
- sub print_thread_entry {
- local($handle, $index) = @_;
- local($i_p0, $filename, $tmpl, $msgnum);
-
- $msgnum = $IndexNum{$index};
- $i_p0 = &fmt_msgnum($msgnum); # Var for replace_li_var
- $filename = &msgnum_filename($msgnum); # Var for replace_li_var
-
- $tmpl = $TLITXT;
- $tmpl =~ s/\$([^\$]*)\$/&replace_li_var($1)/ge;
- print $handle "<LI>", $tmpl, "</LI>\n";
- }
- ##---------------------------------------------------------------------------
- ## Create Index2MsgId if not defined
- ##
- sub defineIndex2MsgId {
- if (!defined(%Index2MsgId)) {
- foreach (keys %MsgId) {
- $Index2MsgId{$MsgId{$_}} = $_;
- }
- }
- }
- ##---------------------------------------------------------------------------
- ## create_routines is used to dynamically create routines that
- ## would benefit from being create at run-time. Routines
- ## that have to check against several regular expressions
- ## are candidates.
- ##
- sub create_routines {
- local($sub) = '';
-
- ##-----------------------------------------------------------------------
- ## exclude_field: Used to determine if field should be excluded from
- ## message header
- ##
- $sub =<<'EndOfRoutine';
- sub exclude_field {
- local($f) = shift;
- local($pat, $ret);
- $ret = 0;
- EXC_FIELD_SW: {
- EndOfRoutine
-
- # Create switch block for checking field against regular
- # expressions (an large || statement could also work).
- foreach $pat (keys %HFieldsExc) {
- $sub .= join('',
- 'if ($f =~ /^',
- $pat,
- '/i) { $ret = 1; last EXC_FIELD_SW; }',
- "\n");
- }
-
- $sub .=<<'EndOfRoutine';
- }
- $ret;
- }
- EndOfRoutine
-
- eval $sub;
- &error("ERROR: Unable to create exclude_field routine:\n\t$@") if $@;
- }
- ##---------------------------------------------------------------------------
- ## Usage routine
- ##
- sub usage {
- select(STDOUT);
- print <<EndOfUsage;
- Usage: $PROG [<options>] <file> ...
- $PROG [<options>] -rmm <msg #> ...
- Options:
- -add : Add message(s) to archive
- -dbfile <name> : Name of MHonArc database file
- (def: ".mhonarc.db")
- -docurl <url> : URL to MHonArc documentation
- (def: "http://www.oac.uci.edu/indiv/ehood/
- mhonarc.html")
- -editidx : Only edit/change index page and messages
- -force : Perform archive operation even if unable to lock
- -footer <file> : File containing user text for bottom of index page
- -genidx : Output index to stdout based upon archive contents
- -header <file> : User text to include at top of index page
- -help : This message
- -idxfname <name> : Name of index page
- (def: "maillist.html")
- -idxsize <#> : Maximum number of messages shown in indexes
- -lockdelay <#> : Time delay, in seconds, between lock tries
- (def: "3")
- -locktries <#> : Maximum number of tries in locking an archive
- (def: "10")
- -mailtourl <url> : URL to use for e-mail address hyperlinks
- (def: "mailto:\$TO\$")
- -maxsize <#> : Maximum number of messages allowed in archive
- -msgsep <exp> : Message separator expression for mailbox files
- (def: "^From ")
- -nodoc : Do not print link to doc at end of index page
- -nomailto : Do not add in mailto links for e-mail addresses
- -nonews : Do not add links to newsgroups
- -noreverse : List messages in normal order
- -nosort : Do not sort messages
- -nothread : Do not create threaded index
- -notsubsort : Do not sort threads by subject
- -outdir <path> : Destination/location of HTML mail archive
- (def: ".")
- -quiet : Suppress status messages during execution
- -rcfile <file> : Resource file for MHonArc
- -reverse : List messages in reverse order
- -rmm : Remove messages from archive
- -savemem : Write message data while processing
- -scan : List out archive contents to stdout
- -single : Convert a single message to HTML
- -sort : Sort by dates (this is the default)
- -subsort : Sort message by subject
- -thread : Create threaded index
- -tidxfname <name> : File name of threaded index page
- (def: "threads.html")
- -time : Print to stderr CPU time used to process mail
- -title <string> : Title of main index page
- (def: "Mail Index")
- -tlevels <#> : Maximum # of nested lists in threaded index
- (def: "3")
- -treverse : List threads with newest thread first
- -tsubsort : Sort threads by subject
- -ttitle <string> : Title of thread index page
- (def: "Mail Thread Index")
- -umask <umask> : Umask of MHonArc process
-
- Description:
- MHonArc is a highly customizable Perl program for converting e-mail into
- HTML. MHonArc will convert UUCP style mailbox files or MH mail folders
- into HTML with an index linking to each mail message. The -single option
- can be used to convert a single mail message.
-
- Read the documentation for more complete usage information.
-
- Version:
- $VERSION
- Copyright (C) 1995,1996 Earl Hood, ehood\@convex.com
- MHonArc comes with ABSOLUTELY NO WARRANTY and MHonArc may be copied only
- under the terms of the GNU General Public License, which may be found in
- the MHonArc distribution.
-
- EndOfUsage
- exit 0;
- }
-